#include "VSSkelecton.h"
#include "VSBoneNode.h"
#include "VSLineSet.h"
#include "VSSkelectonMeshNode.h"
#include "VSGeometryNode.h"
#include "VSGraphicInclude.h"
#include "VSViewFamily.h"
#include "VSDebugDraw.h"
#include "VSStream.h"
using namespace VSEngine2;
IMPLEMENT_RTTI(VSSkelecton,VSNode)
float VSSkelecton::ms_fBoneAxisLength = 1.0f;
BEGIN_ADD_PROPERTY(VSSkelecton,VSNode)
REGISTER_PROPERTY(m_pBoneArray,BoneArray,VSProperty::F_SAVE_LOAD_CLONE)
REGISTER_PROPERTY(m_bIsDrawSkelecton,IsDrawSkelecton,VSProperty::F_SAVE_LOAD_CLONE)
END_ADD_PROPERTY
IMPLEMENT_INITIAL_BEGIN(VSSkelecton)
IMPLEMENT_INITIAL_END
VSSkelecton::VSSkelecton()
{
	m_pBoneArray.Clear();
	m_bIsStatic = 0;
	m_bIsDrawSkelecton = false;


}
VSSkelecton::~VSSkelecton()
{
	m_pBoneArray.Clear();


}
bool VSSkelecton::Register(VSStream & rStream)const
{
	if (rStream.IsObjectRegister(this))
	{
		return 1;
	}
	if(!VSNode::Register(rStream))
		return 0;

	
	for(unsigned int i = 0 ; i < m_pBoneArray.GetNum() ; i++)
		if(m_pBoneArray[i])
		{
			if(!m_pBoneArray[i]->Register(rStream))
				return 0;

		}
	return 1;
}
unsigned int VSSkelecton::DiskUse()const
{
	unsigned int Used = VSNode::DiskUse();
	
	Used +=sizeof(VSBoneNode *) * m_pBoneArray.GetNum();
	Used += sizeof(unsigned int);
	Used += sizeof(bool);
	return Used;
}
bool VSSkelecton::Save(VSStream & rStream,unsigned int &iSaveUse)const
{
	if(!VSNode::Save(rStream,iSaveUse))
		return 0;

	unsigned int uiBoneNum = m_pBoneArray.GetNum();
	if(!rStream.Write(&uiBoneNum,sizeof(unsigned int)))
		return 0;
	iSaveUse += sizeof(unsigned int);

	for(unsigned int i = 0 ; i < uiBoneNum ; i++)
	{
// 		VSBoneNode * pBoneNode = m_pBoneArray[i];
// 		if(!rStream.Write(&pBoneNode,sizeof(VSBoneNode *)))
// 			return 0;
		if(!rStream.WriteObjectPtr(m_pBoneArray[i]))
			return 0;
		iSaveUse += sizeof(VSBoneNode *);
	}

	if(!rStream.Write(&m_bIsDrawSkelecton,sizeof(bool)))
		return 0;
	iSaveUse += sizeof(bool);

	return 1;
}
bool VSSkelecton::Load(VSStream & rStream,unsigned int &iSaveUse)
{	
	if(!VSNode::Load(rStream,iSaveUse))
		return 0;

	unsigned int uiBoneNum = 0;
	if(!rStream.Read(&uiBoneNum,sizeof(unsigned int)))
		return 0;
	iSaveUse += sizeof(unsigned int);

	m_pBoneArray.SetBufferNum(uiBoneNum);
	for(unsigned int i = 0 ; i < uiBoneNum ; i++)
	{
// 		VSBoneNode * pBoneNode;
// 		if(!rStream.Read(&pBoneNode,sizeof(VSBoneNode *)))
// 			return 0;
// 		AddLink(pBoneNode);
		if(!rStream.ReadObjectPtr(m_pBoneArray[i]))
			return 0;
		iSaveUse += sizeof(VSBoneNode *);
	}

	if(!rStream.Read(&m_bIsDrawSkelecton,sizeof(bool)))
		return 0;
	iSaveUse += sizeof(bool);
	return 1;
}
bool VSSkelecton::Link(VSStream & rStream)
{
	if(!VSNode::Link(rStream))
		return 0;
	
	for(unsigned int i = 0 ; i < m_pBoneArray.GetNum() ; i++)
	{
		//m_pBoneArray[i] = (VSBoneNode *)rStream.GetMapValue(GetNextLink());
		rStream.LinkObjectPtr(m_pBoneArray[i]);
	}
	return 1;

}
bool VSSkelecton::Clone(const VSObject *pObject,unsigned int uiType)
{
	const VSSkelecton* Temp = DynamicCast<VSSkelecton>(pObject); 
	if(!Temp)
		return 0;
	if(VSNode::Clone(pObject,uiType))
	{
		LinkBoneArray();
		m_bIsDrawSkelecton = Temp->m_bIsDrawSkelecton;
		return 1;

	}
	else
	{
		return 0;
	}

}

unsigned int VSSkelecton::GetBoneNum()const
{

	return m_pBoneArray.GetNum();
}
int VSSkelecton::GetBoneIndex(const VSUsedName &Name)const
{

	for(unsigned int i = 0 ; i < m_pBoneArray.GetNum() ; i++)
	{
		if(m_pBoneArray[i]->m_cName == Name)
			return i;
	}
	return -1;
}
VSBoneNode *VSSkelecton::GetBoneNode(const VSUsedName& Name)const
{

	for(unsigned int i = 0 ; i < m_pBoneArray.GetNum() ; i++)
	{
		if(m_pBoneArray[i]->m_cName == Name)
			return m_pBoneArray[i];
	}
	return NULL;

}
VSBoneNode * VSSkelecton::GetBoneNode(unsigned int i)const
{
	if(i >= m_pBoneArray.GetNum())
		return NULL;
	return m_pBoneArray[i];
}
void VSSkelecton::CreateBoneOffSetAndOriginMatrix()
{
	m_pBoneArray.Clear();
	VSArray<VSBoneNode *> Temp;
	for(unsigned int i = 0 ; i < m_pChild.GetNum() ;i++)
	{
		VSBoneNode * pBoneNode = DynamicCast<VSBoneNode>(m_pChild[i]);
		if(pBoneNode)
		{

			pBoneNode->CreateBoneOffSetAndOriginMatrix();

				
			
			pBoneNode->GetAllBoneArray(Temp);
		}

	}
	for(unsigned int i = 0 ; i < Temp.GetNum() ; i++)
	{
		VSBoneNode * pBoneNode = DynamicCast<VSBoneNode>(Temp[i]);
		m_pBoneArray.AddElement(pBoneNode);

	}
}
void VSSkelecton::LinkBoneArray()
{
	m_pBoneArray.Clear();
	VSArray<VSBoneNode *> Temp;
	for(unsigned int i = 0 ; i < m_pChild.GetNum() ;i++)
	{
		VSBoneNode * pBoneNode = DynamicCast<VSBoneNode>(m_pChild[i]);
		if(pBoneNode)
		{

			pBoneNode->GetAllBoneArray(Temp);
		}

	}
	for(unsigned int i = 0 ; i < Temp.GetNum() ; i++)
	{
		VSBoneNode * pBoneNode = DynamicCast<VSBoneNode>(Temp[i]);
		m_pBoneArray.AddElement(pBoneNode);

	}
}
void VSSkelecton::UpdateNodeAll(double dAppTime)
{
	if (!m_pParent)
	{
		return ;
	}
	VSSpatial * pMesh = ((VSSkelectonMeshNode *)m_pParent)->GetChild(0);
	if (!pMesh || !m_pChild.GetNum() || !m_bEnable)
	{
		return;
	}

	//VSTransform RootBoneLocTransform , MeshLocTransform;
	//RootBoneLocTransform = m_pChild[0]->GetLocalTransform(); 

	//pMesh->SetLocalMat(RootBoneLocTransform.GetCombine()/* * MeshLocTransform.GetCombine()*/);

	//VSMatrix3X3W IndMat;
	//IndMat.Identity();
	//m_pChild[0]->SetLocalMat(IndMat);
	VSNode::UpdateNodeAll(dAppTime);
	
	
}
void VSSkelecton::ComputeNodeVisibleSet(VSCuller & Culler,bool bNoCull,double dAppTime)
{

	UpDateView(Culler,dAppTime);
	if (m_pNeedDrawNode.GetNum() > 0)
	{
		for (unsigned int i = 0 ; i < m_pNeedDrawNode.GetNum() ; i++)
		{
			if (m_pNeedDrawNode[i])
			{
				m_pNeedDrawNode[i]->ComputeVisibleSet(Culler,bNoCull,dAppTime);
			}
		}
	}
}
void VSSkelecton::UpDateView(VSCuller & Culler,double dAppTime)
{

	VSNode::UpDateView(Culler,dAppTime);
	
	if (Culler.GetCullerType() == VSCuller::CUT_MAIN)
	{
		Draw(Culler.GetCamera());
	}
	

	
}
void VSSkelecton::Draw(VSCamera * pCamera)
{
	if (!pCamera || !m_bIsDrawSkelecton)
	{
		return;
	}

	VSSkelectonMeshNode * pMesh = (VSSkelectonMeshNode *)m_pParent;
	if (!pMesh)
	{
		return ;
	}
	VSVector3 Dist = pCamera->GetWorldTranslate() - pMesh->GetWorldTranslate();
	ms_fBoneAxisLength = Dist.GetLength() * 0.2f;

	static VSArray<VSDebugDraw *> s_DebugDrawArray;
	s_DebugDrawArray.Clear();
	for (unsigned int i = 0 ; i < pCamera->GetViewFamilyNum() ;i++)
	{
		VSViewFamily * pViewFamily = pCamera->GetViewFamily(i);
		if (pViewFamily)
		{
			VSDebugDraw * pDebugDraw = pViewFamily->GetDebugDraw(pMesh->GetRenderGroup());
			if (pDebugDraw && pDebugDraw->m_bEnable)
			{
				s_DebugDrawArray.AddElement(pDebugDraw);
			}
		}
	}
	
	for (unsigned int i = 0 ; i < m_pBoneArray.GetNum() ; i++)
	{
		VSBoneNode * pParent = DynamicCast<VSBoneNode>(m_pBoneArray[i]->GetParent());
		if(pParent)
		{
			VSVector3 P1 = m_pBoneArray[i]->GetWorldTranslate();

			VSVector3 P2 = m_pBoneArray[i]->GetParent()->GetWorldTranslate();
			for (unsigned int j = 0 ; j < s_DebugDrawArray.GetNum() ; j++)
			{
				s_DebugDrawArray[j]->AddDebugLine(P1,P2,VSColorRGBA(1.0f,1.0f,1.0f,1.0f).GetDWARGB(),false);
			}
		}
	}
	for (unsigned int i = 0 ; i < m_pBoneArray.GetNum() ; i++)
	{
		VSVector3 Axis[3];
		VSMatrix3X3 Rot = m_pBoneArray[i]->GetWorldRotate();
		Rot.GetUVN(Axis);
		Axis[0].Normalize();
		Axis[1].Normalize();
		Axis[2].Normalize();
		VSVector3 Pos = m_pBoneArray[i]->GetWorldTranslate();

		for (unsigned int j = 0 ; j < s_DebugDrawArray.GetNum() ; j++)
		{
			s_DebugDrawArray[j]->AddDebugLine(Pos,Pos + Axis[0] * ms_fBoneAxisLength
				,VSColorRGBA(1.0f,0.0f,0.0f,1.0f).GetDWARGB(),false);
		}

		for (unsigned int j = 0 ; j < s_DebugDrawArray.GetNum() ; j++)
		{
			s_DebugDrawArray[j]->AddDebugLine(Pos,Pos + Axis[1] * ms_fBoneAxisLength
				,VSColorRGBA(0.0f,1.0f,0.0f,1.0f).GetDWARGB(),false);
		}

		for (unsigned int j = 0 ; j < s_DebugDrawArray.GetNum() ; j++)
		{
			s_DebugDrawArray[j]->AddDebugLine(Pos,Pos + Axis[2] * ms_fBoneAxisLength
				,VSColorRGBA(0.0f,0.0f,1.0f,1.0f).GetDWARGB(),false);
		}
	}
}